package com.xz.xzutils.module.xzmybatislogplus.socket;

import com.alibaba.fastjson2.JSONObject;
import com.intellij.DynamicBundle;
import com.intellij.openapi.project.Project;
import com.xz.xzutils.components.console.SqlConsole;
import com.xz.xzutils.module.xzmybatislogplus.dto.SocketPort;
import com.xz.xzutils.module.xzmybatislogplus.dto.SqlDTO;
import com.xz.xzutils.settings.mybatislogplus.MybatisLogPlusPersistentState;
import com.xz.xzutils.settings.mybatislogplus.MybatisLogPlusState;
import com.xz.xzutils.utils.MySqlFormatter;

import java.util.ArrayList;
import java.util.List;

/**
 * @author DONG.WANG17@HAND-CHINA.COM
 * @since 2025-02-16 15:41
 */
public class SqlReceiver {
    private final List<SqlDTO> sqlList = new ArrayList<>();
    private final int port;
    private final SqlConsole sqlConsole;
    private final Project project;
    private final DynamicBundle messageBundle = new DynamicBundle(SqlReceiver.class, "messages.MybatisLogPlus");
    private final MybatisLogPlusState mybatisLogPlusState = MybatisLogPlusPersistentState.getInstance().getState();

    public SqlReceiver(int port, SqlConsole sqlConsole, Project project) {
        this.port = port;
        this.sqlConsole = sqlConsole;
        this.project = project;
    }

    public void start() {
        SocketConfig config = new SocketConfig(port);
        config.setReceiveHeartbeatTag(false);
        config.setCallback(new SocketCallback() {
            @Override
            public void onStart() {
                // Sql 解析器启动成功，端口号为：{0}
                sqlConsole.logInfoLn(messageBundle.getMessage("xzmybatislogplus.sql.parser.startup.success", port));
            }

            @Override
            public void onClose() {
                // 移除端口占用
                SocketPort socketPort = project.getUserData(SocketPort.SOCKET_PORT_ENTITY);
                if (socketPort != null) {
                    socketPort.getUsedPorts().remove(port);
                }
                project.putUserData(SocketPort.SOCKET_PORT_ENTITY, socketPort);
                System.out.println("Sql 解析器已关闭，解除端口占用：" + port);
            }

            @Override
            public void onMessage(String message) {
                processSql(message);
            }

            @Override
            public void onError(Exception e) {
                // TODO 正常断开不跑抛异常
                sqlConsole.logErrorLn(e.getMessage());
            }

            @Override
            public void onStatusChange(ConnectionStatus status) {
                SocketCallback.super.onStatusChange(status);
            }
        });

        final SocketEndpoint server = SocketFactory.createServer(config);
        server.start();
    }

    private void processSql(String sqlJson) {
        SqlDTO sqlDTO = JSONObject.parseObject(sqlJson, SqlDTO.class);
        sqlDTO.setFormatted(MySqlFormatter.formatted(sqlDTO.getExecuteSql(), mybatisLogPlusState.getFormatter()));
        sqlDTO.setCompressed(MySqlFormatter.compressed(sqlDTO.getExecuteSql()));
        sqlList.add(sqlDTO);

        // 这里添加业务逻辑：记录到日志、分析SQL等
        // === 项目名 === 序号 === [执行时间 ms] === [SQL_ID]
        this.sqlConsole.logInfoLn(String.format(
                "=== %s === %s === [executeTime: %d ms] === %s",
                project.getName(),
                sqlList.size(),
                sqlDTO.getExecuteTime(),
                sqlDTO.getSqlId()
        ));
        switch (mybatisLogPlusState.getSqlPrintStyle()) {
            case RAW -> {
                if (Boolean.FALSE.equals(sqlDTO.getStatus())) {
                    this.sqlConsole.logErrorLn(sqlDTO.getMessage() + "\n");
                } else {
                    this.sqlConsole.logDebugLn(sqlDTO.getExecuteSql() + "\n");
                }
            }
            case FORMATTED -> {
                if (Boolean.FALSE.equals(sqlDTO.getStatus())) {
                    this.sqlConsole.logErrorLn(sqlDTO.getMessage());
                } else {
                    this.sqlConsole.logDebugLn(sqlDTO.getFormatted());
                }
            }
            case COMPRESSED -> {
                if (Boolean.FALSE.equals(sqlDTO.getStatus())) {
                    this.sqlConsole.logErrorLn(sqlDTO.getMessage() + "\n");
                } else {
                    this.sqlConsole.logDebugLn(sqlDTO.getCompressed() + "\n");
                }
            }
        }
    }
}
